#include "my_container.h"

void my_container ::copy_data(int * dest, const int * source, size_t len)
{
   for (int i = 0; i < len; i++)
      dest[i] = source[i];
}


my_container :: my_container() : size_(0), capacity_(1)
{
}

my_container :: my_container(const my_container& x) : size_(x.size_)
{
   capacity_ = 1;
   check_capacity(x.size_);
   if(size_ > 1)
      copy_data(data_.digits_, x.data_.digits_, size_);
      //memcpy(data_.digits_, x.data_.digits_, size_ * sizeof(int));
   else
      data_.first_digit_ = x.data_.first_digit_;
}

void my_container :: check_capacity(size_t new_capacity_)
{
   if (new_capacity_ > std :: max(capacity_, static_cast<size_t>(1)))
      expand();
   else
   {
      if ((new_capacity_ * 4 < capacity_) || (size_ == 1))
         shrink();
   }
}

void my_container :: expand()
{
   capacity_ *= static_cast <size_t> (2);
   int *tmp_digits = new int [capacity_];
   if (size_ > 1)
   {
      copy_data(tmp_digits, data_.digits_, size_);
      delete [] data_.digits_;
   }
   else
      tmp_digits[0] = data_.first_digit_;
   data_.digits_ = tmp_digits;
}

void my_container :: shrink()
{
   if (capacity_ != 1)
   {
      capacity_ /= 2;
      if (size_ != 1)
      {
         int *tmp_digits = new int [capacity_];
         copy_data(tmp_digits, data_.digits_, size_);
         //memcpy(tmp_digits, data_.digits_, size_ * sizeof(int));
         delete[] (data_.digits_);
         data_.digits_ = tmp_digits;
      }
      else
      {
         capacity_ = 1;
         data_.digits_ = new int [capacity_];
         data_.first_digit_ = (*this)[0];
      }
   }
}

my_container :: my_container (size_t lenght, int val)
{
   size_ = lenght;
   if (lenght == 1)
   {
      capacity_ = 1;
    //  data_.digits_ = new int [capacity_];
      data_.first_digit_ = val;
   }
   else
   {
      capacity_ = 2 * lenght;
      data_.digits_ = new int [capacity_];
      for (size_t i = 0; i < size_; i++)
         data_.digits_[i] = val;
   }
}

size_t my_container :: size() const
{
   return size_;
}

size_t my_container :: capacity() const
{
   return capacity_;
}

my_container& my_container :: operator= (const my_container& x)
{
   if (this != &x)
   {
      if(size_ > 1)
         delete[] data_.digits_;
      capacity_ = x.capacity_;
      size_ = x.size_;
      if (size_ <= 1)
         data_.first_digit_ = x.data_.first_digit_;
      else
      {
         data_.digits_ = new int [capacity_];
         copy_data(data_.digits_, x.data_.digits_, size_);
         //memcpy(data_.digits_, x.data_.digits_, size_ * sizeof(int));
      }
   }
   return *this;
}

int & my_container:: operator[](size_t index)
{
   if (capacity_ != 1)
      return data_.digits_[index];
   else
      return data_.first_digit_;
}

const int & my_container:: operator[](size_t index) const
{
   if (size_ != 1)
      return data_.digits_[index];
   else
      return data_.first_digit_;
}

int& my_container :: back()
{
   return (*this)[size_ - 1];
}

const int & my_container :: back() const
{
   return (*this)[size_ - 1];
}

void my_container :: push_back (int x)
{
   check_capacity(size_ + 1);
   (*this)[size_++] = x;
}

void my_container :: pop_back()
{
   check_capacity(--size_);
}

void my_container :: swap(my_container &x)
{
   std :: swap(size_, x.size_);
   std :: swap(capacity_, x.capacity_);
   std :: swap(data_, x.data_);
}

void my_container :: resize(size_t new_size_)
{
   if (new_size_ != 1)
   {
      int *tmp = new int [new_size_];
      memcpy(tmp, data_.digits_, (std :: min(size_, new_size_)) * (sizeof(int)));
      if (capacity_ > 1)
         delete[] data_.digits_;
      data_.digits_ = tmp;
   }
   else
   {
      data_.first_digit_ = (*this)[0];
      if (capacity_ > 1)
         delete[] data_.digits_;
   }
   size_ = new_size_;
   capacity_ = new_size_; 
}

void my_container :: reverse()
{
   if(size_ != 1)
   {
      for (size_t i = 0; i < size_ / 2; i++)
      {
         std :: swap((*this)[i] , (*this)[size_ - 1 - i]);
      }
   }
}

std :: ofstream & operator <<(std :: ofstream &out, const my_container &x)
{
   for (size_t i = 0; i < x.size(); i++)
      out << x[i] << " ";
   return out;
}